package bocchi.action;

import com.megacrit.cardcrawl.actions.AbstractGameAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.cards.AbstractCard.CardColor;
import com.megacrit.cardcrawl.cards.AbstractCard.CardRarity;
import com.megacrit.cardcrawl.cards.AbstractCard.CardTags;
import com.megacrit.cardcrawl.cards.AbstractCard.CardType;
import com.megacrit.cardcrawl.cards.CardGroup;
import com.megacrit.cardcrawl.cards.CardGroup.CardGroupType;
import com.megacrit.cardcrawl.cards.blue.Strike_Blue;
import com.megacrit.cardcrawl.cards.green.Strike_Green;
import com.megacrit.cardcrawl.cards.red.Strike_Red;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.helpers.CardLibrary;
import com.megacrit.cardcrawl.screens.CardRewardScreen;
import com.megacrit.cardcrawl.unlock.UnlockTracker;
import com.megacrit.cardcrawl.vfx.cardManip.ShowCardAndAddToDiscardEffect;
import com.megacrit.cardcrawl.vfx.cardManip.ShowCardAndAddToHandEffect;

import java.util.ArrayList;
import java.util.Map;

public class CustomDiscoveryAction extends AbstractGameAction {
    private boolean retrieveCard = false;
    private final boolean upgraded;
    private final boolean costFree;
    private final boolean rollRarity;
    private final CardGroup cardPool;

    public CustomDiscoveryAction(CardGroup cardPool, boolean upgraded, boolean costFree, boolean rollRarity) {
        this.actionType = ActionType.CARD_MANIPULATION;
        this.duration = Settings.ACTION_DUR_FAST;
        this.cardPool = cardPool;
        this.upgraded = upgraded;
        this.costFree = costFree;
        this.rollRarity = rollRarity;

        if (cardPool.size() < 3) {
            this.cardPool.clear();
            this.cardPool.addToBottom(new Strike_Red());
            this.cardPool.addToBottom(new Strike_Green());
            this.cardPool.addToBottom(new Strike_Blue());
        }
    }

    public CustomDiscoveryAction(String[] ids, boolean upgraded, boolean costFree, boolean rollRarity) {
        this(getCardPool(ids), upgraded, costFree, rollRarity);
    }

    public CustomDiscoveryAction(CardColor color, CardType type, CardRarity rarity, boolean upgraded, boolean costFree, boolean rollRarity) {
        this(getCardPool(color, type, rarity), upgraded, costFree, rollRarity && rarity == null);
    }

    public void update() {
        if (this.duration == Settings.ACTION_DUR_FAST) {
            AbstractDungeon.cardRewardScreen.customCombatOpen(generateCardChoices(), CardRewardScreen.TEXT[1], true);
            tickDuration();
            return;
        }

        if (!this.retrieveCard) {
            if (AbstractDungeon.cardRewardScreen.discoveryCard != null) {
                AbstractCard card = AbstractDungeon.cardRewardScreen.discoveryCard.makeStatEquivalentCopy();
                if (this.upgraded) card.upgrade();
                if (this.costFree) card.setCostForTurn(0);

                card.current_x = -1000.0F * Settings.xScale;
                if (AbstractDungeon.player.hand.size() < 10) {
                    AbstractDungeon.effectList.add(new ShowCardAndAddToHandEffect(card, (float) Settings.WIDTH / 2.0F, (float) Settings.HEIGHT / 2.0F));
                } else {
                    AbstractDungeon.effectList.add(new ShowCardAndAddToDiscardEffect(card, (float) Settings.WIDTH / 2.0F, (float) Settings.HEIGHT / 2.0F));
                }

                AbstractDungeon.cardRewardScreen.discoveryCard = null;
            }

            this.retrieveCard = true;
        }

        tickDuration();
    }

    private ArrayList<AbstractCard> generateCardChoices() {
        ArrayList<AbstractCard> cardChoices = new ArrayList<>();

        while (cardChoices.size() < 3) {
            AbstractCard newCard;
            if (rollRarity) {
                newCard = cardPool.getRandomCard(true, rollRarity());
            } else {
                newCard = cardPool.getRandomCard(true);
            }

            boolean isDuplicate = false;
            for (AbstractCard card : cardChoices) {
                if (card.cardID.equals(newCard.cardID)) {
                    isDuplicate = true;
                    break;
                }
            }

            if (!isDuplicate) {
                cardChoices.add(newCard.makeCopy());
            }
        }

        return cardChoices;
    }

    private static CardRarity rollRarity() {
        int roll = AbstractDungeon.cardRandomRng.random(99);
        if (roll < 55) {
            return CardRarity.COMMON;
        } else if (roll < 85) {
            return CardRarity.UNCOMMON;
        } else {
            return CardRarity.RARE;
        }
    }

    private static CardGroup getCardPool(String[] ids) {
        CardGroup cardPool = new CardGroup(CardGroupType.UNSPECIFIED);

        for (String id : ids) {
            AbstractCard card = CardLibrary.getCard(id);
            if (card != null) {
                cardPool.addToBottom(card);
            }
        }

        return cardPool;
    }

    private static CardGroup getCardPool(CardColor color, CardType type, CardRarity rarity) {
        CardGroup cardPool = new CardGroup(CardGroupType.UNSPECIFIED);

        for (Map.Entry<String, AbstractCard> entry : CardLibrary.cards.entrySet()) {
            AbstractCard card = entry.getValue();

            if (color != null && card.color != color) continue;
            if (type != null && card.type != type) continue;
            if (rarity != null && card.rarity != rarity) continue;
            if (card.hasTag(CardTags.HEALING)) continue;
            if (card.type == CardType.CURSE) continue;
            if (card.type == CardType.STATUS) continue;
            if (UnlockTracker.isCardLocked(entry.getKey()) && !Settings.treatEverythingAsUnlocked()) continue;

            cardPool.addToBottom(card);
        }

        return cardPool;
    }
}
